// 命令式

import deepcopy from "deepcopy";
import { events } from "./events";
import { onUnmounted } from "vue";

export function useCommand(data, focusData) {
  const state = {
    current: -1, // 前进后退的指针
    queue: [], // 队列
    commands: {}, // 存储命令和执行命令的映射表， name: ()=>{}
    commandArray: [], // 存储所有的命令
    destroyArray: [], // 销毁命令列表  bind('click')   unbind('click')
  };

  // 命令注册函数， 将命令注册到队列中
  const registry = (command) => {
    state.commandArray.push(command); // 存储所有的命令
    state.commands[command.name] = (...args) => {
      const { redo, undo } = command.execute(...args);
      redo();
      // debugger
      // 是否需要存入列表
      if (command.pushQueue) {
        let { queue, current } = state; // 当前队列 指针

        // 如果撤销后再压入新的操作，则需要去掉current指针右边的状态
        if (queue.length > 0) {
          queue = queue.slice(0, current + 1); // 截取一个新的队列
          state.queue = queue;
        }

        // 入队操作
        queue.push({ redo, undo }); // 命令入队
        state.current = current + 1; // 指针前进一步
        console.log("queue:", queue, state);
      }
    };
  };

  // 恢复命令
  // 每个命令都有 name, execute  固定写法
  registry({
    name: "redo",
    keyboard: "ctrl+y",
    execute() {
      // 命令执行函数
      return {
        // 将指针前进一步
        redo() {
          let item = state.queue[state.current + 1];
          if (item) {
            item.redo && item.redo(); // 恢复状态 将指针对应的值赋给model重新渲染
            state.current++;
          }
        },
      };
    },
  });

  // 撤销命令
  registry({
    name: "undo",
    keyboard: "ctrl+z",
    execute() {
      return {
        redo() {
          if (state.current == -1) return; // 无需撤销
          let item = state.queue[state.current];
          if (item) {
            item.undo && item.undo(); // 撤销操作
            state.current--;
          }
        },
      };
    },
  });

  // 拖动拖入命令
  registry({
    name: "drag",
    pushQueue: true, // 表示该操作需要入队列
    init() {
      this.before = null; // 之前状态
      // 开始拖动时触发， 记录当前未拖动时的组件状态
      const start = () => {
        this.before = deepcopy(data.value.blocks);
      };
      // 结束  将拖动后的状态压入队列中
      const end = () => {
        state.commands.drag();
      };
      // 事件绑定
      events.on("start", start);
      events.on("end", end);

      return () => {
        // 销毁函数
        events.off("start", start);
        events.off("end", end);
      };
    },
    execute() {
      let before = this.before; // 之前的状态
      let after = data.value.blocks; // 当前的状态

      return {
        redo() {
          // 恢复, 一松鼠标，直接把当前的组件状态入列
          data.value = { ...data.value, blocks: after };
        },
        undo() {
          // 撤销
          data.value = { ...data.value, blocks: before };
        },
      };
    },
  });

  // 导入操作需要记录历史
  registry({
    name: "updateContainer", // 更新容器
    pushQueue: true, // 需要入队操作
    execute(newValue) {
      let state = {
        before: data.value, // 旧值
        after: newValue, // 新值
      };
      return {
        redo: () => {
          data.value = state.after;
        },
        undo: () => {
          data.value = state.before;
        },
      };
    },
  });

  // 元素置顶
  registry({
    name: "placeTop",
    pushQueue: true,
    execute() {
      let before = deepcopy(data.value.blocks);
      let after = (() => {
        let { focus, unfocused } = focusData.value;

        // 得到未选中元素中的最大的zindex
        // 从小到大查找最大的zindex
        let maxZIndex = unfocused.reduce((prev, block) => {
          return Math.max(prev, block.zIndex);
        }, -Infinity);

        // 将选中的元素的zindex=maxZindex+1
        focus.forEach((block) => (block.zIndex = maxZIndex + 1));

        return data.value.blocks;
      })();

      return {
        undo: () => {
          data.value = { ...data.value, blocks: before };
        },
        redo: () => {
          data.value = { ...data.value, blocks: after };
        },
      };
    },
  });

  // 元素置底
  registry({
    name: "placeBottom",
    pushQueue: true,
    execute() {
      let before = deepcopy(data.value.blocks);
      let after = (() => {
        let { focus, unfocused } = focusData.value;

        // 查找未选中元素列表中最小的zindex
        let minZindex =
          unfocused.reduce((prev, block) => {
            return Math.min(prev, block.zIndex);
          }, Infinity) - 1; // 从大往小查找

        if (minZindex < 0) {
          // 要将所有未选中的列表元素的zinde都加1
          const dur = Math.abs(minZindex);
          minZindex = 0;
          // 未选中元素都加上dur
          unfocused.forEach((block) => (block.zIndex += dur));
        }

        // 设置选中的元素zindex=最小的索引
        focus.forEach((block) => (block.zIndex = minZindex));

        return data.value.blocks;
      })();

      return {
        undo: () => {
          data.value = { ...data.value, blocks: before };
        },
        redo: () => {
          data.value = { ...data.value, blocks: after };
        },
      };
    },
  });

  // 元素删除
  registry({
    name: "delete",
    pushQueue: true,
    execute() {
      let state = {
        before: deepcopy(data.value.blocks), // 当前的所有元素
        after: focusData.value.unfocused, // 未选中的元素
      };
      return {
        undo: () => {
          data.value = { ...data.value, blocks: state.before };
        },
        redo: () => {
          data.value = { ...data.value, blocks: state.after };
        },
      };
    },
  });

  // 更新单个组件
  registry({
    name: "updateBlock",
    pushQueue: true,
    execute(newBlock, oldBlock) {
      let state = {
        before: deepcopy(data.value.blocks),
        after: (() => {
          let blocks = [...data.value.blocks];
          // 旧值索引
          const index = data.value.blocks.indexOf(oldBlock);
          if (index > -1) {
            blocks.splice(index, 1, newBlock);
          }
          return blocks; // 替换后的blocks
        })(),
      };
      return {
        redo: () => {
          data.value = { ...data.value, blocks: state.after };
        },
        undo: () => {
          data.value = { ...data.value, blocks: state.before };
        },
      };
    },
  });

  // 更新绘图区大小
  registry({
    name: "updateModelValue",
    execute: (val) => {
      const state = {
        before: deepcopy(data.value),
        after: deepcopy(val),
      };
      return {
        redo: () => {
          data.value = state.after;
        },
        undo: () => {
          data.value = state.before;
        },
      };
    },
  });

  // 键盘事件
  const keyboardEvent = (() => {
    const keyCodes = {
      90: "z",
      89: "y",
    };
    const onKeydown = (e) => {
      const { ctrlKey, keyCode } = e; // keyCode==90
      let keyString = [];
      // 如果按下ctrl
      if (ctrlKey) keyString.push("ctrl");
      // 存入按下的字母的ascii
      keyString.push(keyCodes[keyCode]);
      // 将数组中的字符拼接
      keyString = keyString.join("+"); // ctrl+z

      state.commandArray.forEach(({ keyboard, name }) => {
        if (!keyboard) return; // 如果没有快捷键则忽略
        if (keyboard == keyString) {
          state.commands[name](); // 执行命令
          e.preventDefault(); // 阻止默认行为
        }
      });
      console.log("按下键盘", keyString);
    };
    const init = () => {
      window.addEventListener("keydown", onKeydown);
      return () => {
        // 注销事件监听
        window.removeEventListener("keydown", onKeydown);
      };
    };
    return init;
  })();

  // 初始化
  (() => {
    // 绑定键盘事件
    state.destroyArray.push(keyboardEvent());
    // 命令初始化  将init的返回函数存入destroyArray
    state.commandArray.forEach((command) => command.init && state.destroyArray.push(command.init()));
  })();

  // 函数销毁
  onUnmounted(() => {
    state.destroyArray.forEach((fn) => fn && fn());
  });

  return state;
}
